/**
 * Copyright (c) 2007,中企动力华南研发中心<br>
 * All rights reserved.
 */
package com.ce.pms.charge.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.ce.pms.base.service.impl.PmsBaseServiceImpl;
import com.ce.pms.charge.dao.IArCalculateDao;
import com.ce.pms.charge.dao.IBusinessCodeDao;
import com.ce.pms.charge.dao.ICharStoChoMeterDao;
import com.ce.pms.charge.dao.IFlowDefDao;
import com.ce.pms.charge.dao.IGeneralVersionDao;
import com.ce.pms.charge.dao.IMeterDataRegisterDao;
import com.ce.pms.charge.dao.IMeterVersionDao;
import com.ce.pms.charge.dao.IPeriodLogDao;
import com.ce.pms.charge.dao.ISubAccountDao;
import com.ce.pms.charge.model.ArCalculateModel;
import com.ce.pms.charge.model.CharStaChoDomain;
import com.ce.pms.charge.model.ChargeAccountDomain;
import com.ce.pms.charge.model.ChargeDatasDomain;
import com.ce.pms.charge.model.DebitTransDomain;
import com.ce.pms.charge.model.GeneralVersion;
import com.ce.pms.charge.model.MeterVersion;
import com.ce.pms.charge.model.PeriodDomain;
import com.ce.pms.charge.model.PeriodLogDomain;
import com.ce.pms.charge.service.IArCalculateService;
import com.ce.pms.charge.vo.ArCalculateVO;
import com.ce.pms.charge.vo.SubAccountBean;
import com.ce.pms.common.model.SysInfo;
import com.ce.pms.common.model.SysrefcodeDO;
import com.ce.pms.exception.BusinessException;
import com.ce.pms.house.dao.IHouseDao;
import com.ce.pms.house.model.BuildingDomain;
import com.ce.pms.house.model.HouseDomain;
import com.sitechasia.webx.core.support.Page;

/**
 * 功能描述：应收计算<br>
 * @author 罗军林 创建日期：2008-8-27
 */
public class ArCalculateServiceImpl extends PmsBaseServiceImpl implements IArCalculateService {

	/**
	 * 分批计算量
	 */
	private final int PAGESIZE=500;

	private final int FIXED=1;

	private final int GENERAL=0;

	//帐户余额MAP，主键为主帐户ID，value为余额
	private ThreadLocal<Map<Long,BigDecimal>> subAccountBalances=new ThreadLocal<Map<Long,BigDecimal>>();
	//所有有效的走表版本
	private ThreadLocal<Map<Object,MeterVersion>> meterVersionCache=new ThreadLocal<Map<Object,MeterVersion>>();

	private IMeterVersionDao meterVersionDao;
	private IHouseDao houseDao;
	private IBusinessCodeDao businessCodeDao;
	private ISubAccountDao subAccountDao;
	private IPeriodLogDao periodLogDao;
	private IFlowDefDao flowDefDao;
	private IGeneralVersionDao generalVersionDao;
	private ICharStoChoMeterDao charStoChoMeterDao;
	private IArCalculateDao arCalculateDao;


	/**
	 * 功能描述:应收计算<br>
	 * 实现思路：
	 * 先遍历当前有效收费周期下的收费管理区，再遍历收费管理区下的楼栋，
	 * 以楼栋为单位进行入帐，考虑到楼栋下的楼栋数量可能会很庞大，采取
	 * 分页的形式
	 * Create author:罗军林<br>
	 * Create on:2008-9-8<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	 public void calculate(Long userId){
		Long starttime=System.currentTimeMillis();
		logger.info("开始应收计算...");

		meterVersionCache.set(new HashMap<Object, MeterVersion>());
		subAccountBalances.set(new HashMap<Long, BigDecimal>());

		loadMeterVersionCache();
		List<PeriodDomain> periodList = arCalculateDao.getPeriodList();
		checkIsCaculate(periodList);
		synchronized (this) {
			for(PeriodDomain period : periodList){
				List<Object[]> datasRTransaction=new ArrayList<Object[]>();//原始数据及交易数据集

				List<String> datas=new ArrayList<String>();//原始数据集合

				Date startTime=this.getDate();

				Map<Long,SubAccountBean> subAccount=arCalculateDao.querySubaccount(period.getChargePrecinct().getKeyword());

				comptabiliserWithChargePrecinct(GENERAL,userId, period,subAccount);

				comptabiliserWithChargePrecinct(FIXED,userId, period,subAccount);

				meterComptabilise(userId,period,subAccount,datasRTransaction,datas);

				updateSubAccountBalance();

				addBatchDatasRTransaction(datasRTransaction);

				updateBatchDatasStatus(datas);

				arCalculateDao.updateMtranId();

				savePeriodLog(userId, period, startTime);

				}
		}
		logger.info("应收计算完成，所花费时间为："+(System.currentTimeMillis()-starttime));

//		subAccountBalances=new HashMap<Long, BigDecimal>();
//		meterVersionCache=new HashMap<Object, MeterVersion>();
	}

	/**
	 * 功能描述:计算指定原始数据费用<br>
	 * @param chargeAccountDomain
	 * @param newChargeDatas
	 * @param oldChargeDatasId
	 * @param userId<br>
	 * Create author:罗军林<br>
	 * Create on:2008-10-9<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	public void calculate(ChargeAccountDomain chargeAccountDomain,ChargeDatasDomain newChargeDatas,Long oldChargeDatasId,Long userId){
//		if(null != oldChargeDatasId){
//			DebitTransDomain debit= arCalculateDao.findDebitTransByChargeDatasId(oldChargeDatasId);
//			chargeAccountDomain.setBalance(chargeAccountDomain.getBalance().subtract(debit.getDebit()));
//			arCalculateDao.deleteObject(debit);
//		}

		checkParameterIsNull(chargeAccountDomain, "charge_not_null");
		checkParameterIsNull(newChargeDatas, "charge:chargedata_not_null");


		List<CharStaChoDomain> charStaChoDomainList = charStoChoMeterDao.queryCharStoCho(
				newChargeDatas.getHouse().getKeyword(), newChargeDatas.getMeter().getKeyword());
		for(CharStaChoDomain charStaChoDomain : charStaChoDomainList){
			checkParameterIsNull(charStaChoDomain, "charge:no_chargeStaCho");

			MeterVersion meterVersion=(MeterVersion)charStaChoDomain.getChargeSta().getCVersion();
			BigDecimal amount = getAmount(newChargeDatas.getWastage(), meterVersion);
			BigDecimal amt = meterVersion.calculate(amount); //应收费用
			if(amt==null || BigDecimal.ZERO.compareTo(amt)>=0){
				return;
			}

			//新增交易
			DebitTransDomain debitTransDomain=new DebitTransDomain();
			debitTransDomain.setBindingAccount(chargeAccountDomain);
			debitTransDomain.setDebit(amt);
			debitTransDomain.setBusinessCode(charStaChoDomain.getChargeItem().getBizCode());
			debitTransDomain.setClazz(SysrefcodeDO.FEE_TRANSACTION_CLAZZ_PRINCIPAL);
			debitTransDomain.setStatuz(SysrefcodeDO.FEE_TRANSACTION_STATUZ_NOTPAY);
			debitTransDomain.setPeriod(newChargeDatas.getPeriod());
			debitTransDomain.setHouse(newChargeDatas.getHouse());
			debitTransDomain.setStaVersion(meterVersion);
			debitTransDomain.setSysInfo(createInfo(userId));
			arCalculateDao.saveObject(debitTransDomain);
			debitTransDomain.setMTransId(debitTransDomain.getTransactionId());

			//新增交易与原始数据的关系
			List<Object[]> datasRTransaction=new ArrayList<Object[]>();
			datasRTransaction.add(new Object[]{newChargeDatas.getChargeDataId(),debitTransDomain.getTransactionId()});
			arCalculateDao.addBatchDatasRTransaction(datasRTransaction);

			//修改原始数据状态
			newChargeDatas.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_COUNTED);

			//更新余额
			chargeAccountDomain.setBalance(chargeAccountDomain.getBalance().add(amt));
		}
	}

	/**
	 * 功能描述:获取用量<br>
	 * @param wastage 用量
	 * @param meterVersion
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-10-9<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private BigDecimal getAmount(BigDecimal wastage, MeterVersion meterVersion) {
		BigDecimal amount=wastage.multiply(meterVersion.getDynameter());
		if(BigDecimal.ZERO.compareTo(amount)==0){
			if(SysrefcodeDO.CONSTANTS_ONE.equals( meterVersion.getZeroSelect() )){
				amount=BigDecimal.ZERO;
			}else if(SysrefcodeDO.CONSTANTS_ZERO.equals( meterVersion.getZeroSelect()) ){
				amount=meterVersion.getLQuantity();
			}else{
				throw new BusinessException("charge:zero_min_amount",BusinessException.ERROR);
			}
		}else{
			if(SysrefcodeDO.CONSTANTS_ONE.equals(meterVersion.getZeroSelect()) &&
					amount.compareTo(meterVersion.getLQuantity())<0){
				amount=meterVersion.getLQuantity();
			}
		}
		if(BigDecimal.ZERO.compareTo(amount)==0){
			throw new BusinessException("charge:amount_is_zero_info",BusinessException.ERROR);
		}
		return amount;
	}

	public Page queryGeneralTran(ArCalculateVO searchCondition){
		searchCondition.setChrgType(SysrefcodeDO.FEE_CHAR_TYPE_CLASS_CODE_GENERAL);
		Page page=arCalculateDao.queryDebitTrans(searchCondition);
		List<DebitTransDomain> translist= page.getResult();

		List<ArCalculateVO> tempList = convertGeneralDoToVO(translist);
		page.setResult(tempList);

		return page;
	}

	public Page queryMeterTran(ArCalculateVO searchCondition){
		searchCondition.setChrgType(SysrefcodeDO.FEE_CHAR_TYPE_CLASS_CODE_METER);
		Page page=arCalculateDao.queryDebitTrans(searchCondition);
		List<DebitTransDomain> translist= page.getResult();

		List<ArCalculateVO> tempList = convertMeterDoToVO(translist);
		page.setResult(tempList);

		return page;
	}

	public Page queryOtherTran(ArCalculateVO searchCondition){
		searchCondition.setChrgType("other");
		Page page=arCalculateDao.queryDebitTrans(searchCondition);
		List<DebitTransDomain> translist= page.getResult();

		List<ArCalculateVO> tempList = convertOtherDoToVO(translist);
		page.setResult(tempList);

		return page;
	}


	public Page queryChargeTotalList(ArCalculateVO searchCondition){

		return arCalculateDao.queryChargeTotalList(searchCondition);
	}

	/**
	 * 功能描述:保存帐期日志<br>
	 * @param userId
	 * @param period
	 * @param startTime<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-12<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void savePeriodLog(Long userId, PeriodDomain period, Date startTime) {
		PeriodLogDomain periodLog=new PeriodLogDomain();
		periodLog.setStartTime(startTime);
		periodLog.setEndTime(this.getDate());
		periodLog.setPeriod(period);
		periodLog.setCreator(userId);
		periodLog.setFlowDef(flowDefDao.findFlowDefBySEQ(SysrefcodeDO.FEE_FLOW_DEF_NAME_RECEIVABLE));
		periodLogDao.saveObject(periodLog);
	}


	/**
	 * 功能描述:<br>
	 * @param translist
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-11<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private List<ArCalculateVO> convertMeterDoToVO(List<DebitTransDomain> translist) {
		List<ArCalculateVO> tempList=new ArrayList<ArCalculateVO>();
		for(DebitTransDomain tran : translist){
			ArCalculateVO arcalculateVo = convertTranToVo(tran);
			Map<Long,String> dataIds=new HashMap<Long, String>();
			StringBuffer meterName=new StringBuffer();
			BigDecimal wastage=new BigDecimal(0);
			for(ChargeDatasDomain data : tran.getChargeDatas()){
				dataIds.put(data.getMeter().getKeyword(), data.getMeter().getName());
				//meterName.append(data.getMeter().getName()).append(",");
				wastage=wastage.add(data.getWastage());
			}
			for(Long dataId : dataIds.keySet()){
				meterName.append(dataIds.get(dataId)).append(",");
			}
			if(meterName.length()>0 && ','==meterName.charAt(meterName.length()-1)){
				meterName.deleteCharAt(meterName.length()-1);
			}
			arcalculateVo.setMeterName(meterName.toString());
			arcalculateVo.setWastage(wastage);



			tempList.add(arcalculateVo);
		}
		return tempList;
	}

	/** 功能描述:<br>
	 * @param translist
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-11<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private List<ArCalculateVO> convertGeneralDoToVO(List<DebitTransDomain> translist) {
		List<ArCalculateVO> tempList=new ArrayList<ArCalculateVO>();
		for(DebitTransDomain tran : translist){
			ArCalculateVO arcalculateVo = convertTranToVo(tran);
			arcalculateVo.setCalculateSize(getCalculateSize(tran));
			tempList.add(arcalculateVo);
		}
		return tempList;
	}

	/**
	 * 功能描述:<br>
	 * @param translist
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-11<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private List<ArCalculateVO> convertOtherDoToVO(List<DebitTransDomain> translist) {
		List<ArCalculateVO> tempList=new ArrayList<ArCalculateVO>();
		for(DebitTransDomain tran : translist){
			ArCalculateVO arcalculateVo = convertTranToVo(tran);
			tempList.add(arcalculateVo);
		}
		return tempList;
	}

	/** 功能描述:<br>
	 * @param tran
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-11<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private ArCalculateVO convertTranToVo(DebitTransDomain tran) {
		ArCalculateVO arcalculateVo=new ArCalculateVO();
		arcalculateVo.setAmt(tran.getDebit());
		arcalculateVo.setBuildingId(tran.getHouse().getBuilding().getKeyword());
		arcalculateVo.setBuildingName(tran.getHouse().getBuilding().getName());
		arcalculateVo.setChargeItemId(tran.getStaVersion().getChargeSta().getChargeItem().getKeyword());
		arcalculateVo.setChargeItemName(tran.getStaVersion().getChargeSta().getChargeItem().getItemName());
		arcalculateVo.setHouseNumber(tran.getHouse().getHouseNumber());
		arcalculateVo.setPeriodId(tran.getPeriod().getKeyword());
		arcalculateVo.setPeriodName(tran.getPeriod().getPeriod());
		return arcalculateVo;
	}

	/**
	 * 功能描述:根据收费版本定义的类型，找出所计算的面积<br>
	 * @param tran<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private BigDecimal getCalculateSize(DebitTransDomain tran) {
		GeneralVersion gerneralVersion=generalVersionDao.findById(tran.getStaVersion().getStaHisId());
		if( SysrefcodeDO.FEE_CHARGESTA_CAST_VALUE_BUILDAREA.equals( gerneralVersion.getCountParameter())){
			return tran.getHouse().getBuildSize();
		}else if(SysrefcodeDO.FEE_CHARGESTA_CAST_VALUE_SETAREA.equals( gerneralVersion.getCountParameter())){
			return tran.getHouse().getInnerSize();
		}else{
			throw new BusinessException("charge:count_parameter_error",BusinessException.ERROR);
		}
	}

	private void loadMeterVersionCache(){
		List<MeterVersion> meterVersionList=meterVersionDao.findAllValidMeterVersion();
		for(MeterVersion item : meterVersionList){
			meterVersionCache.get().put(item.getStaHisId(), item);
		}
	}

	/**
	 * 功能描述:走表费用的入帐操作<br>
	 * @param userId
	 * @param period
	 * @param subAccount<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void meterComptabilise(Long userId, PeriodDomain period,Map<Long,SubAccountBean> subAccount,final List<Object[]> datasRTransaction,final List<String> datas){
		SysInfo currentSysInfo=createInfo(userId);//当前用户信息
		Set<BuildingDomain> buildings = period.getChargePrecinct().getBuildings();
		for(BuildingDomain building :  buildings){
			logger.info("楼栋："+building.getKeyword()+":"+building.getName());
			int pageNO=1;
			List<ArCalculateModel> houseList;
			do{
				Long s=System.currentTimeMillis();
				houseList=arCalculateDao.getHouseListWithMeter(period, building.getKeyword(), pageNO,PAGESIZE);
				logger.info("走表费用查询时间："+(System.currentTimeMillis()-s));
				for(int i=0;i<houseList.size();i++){
					ArCalculateModel houseItem= houseList.get(i);
					SubAccountBean subAccountBean = subAccount.get(houseItem.getHouseId());
					if(!checkSubAccountStatus(houseItem.getHouseId(), subAccountBean)){
						continue;
					}

					MeterVersion meterVersion=meterVersionCache.get().get( houseItem.getChargeStaVerionId() );
					BigDecimal amt= meterVersion.calculate(houseItem.getWastage());

					if(amt!=null && BigDecimal.ZERO.compareTo(amt)<0){
						DebitTransDomain debitTransDomain = saveMeterDebitTransDomain(currentSysInfo, period, subAccountBean.getSubAccountId(), houseItem, meterVersion, amt);
						addDatasRtransaction(houseItem.getChargeDatasIds(), debitTransDomain.getTransactionId(),datasRTransaction);
					}

					addDatas(houseItem.getChargeDatasIds(),datas);
					addBalance(subAccountBean.getSubAccountId(), amt);
					flushClear(i);
				}
				pageNO++;
			}while( houseList!=null && houseList.size()==PAGESIZE);
		}
		logger.info("走表数据计算了"+datasRTransaction.size()+"条");
	}

	/**
	 * 功能描述:每插入25条记录，清除一下，以保证内存不被溢出<br>
	 * @param i<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void flushClear(int i) {
		if(i%25==0){
			arCalculateDao.flush();
			arCalculateDao.clear();
		}
	}

	/**
	 * 功能描述:将本次参与计算的原始数据添加至缓存<br>
	 * @param houseItem
	 * @param transactionId<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void addDatas(String chargeDatasIds, final List<String> datas) {
		String dataIDs[]=chargeDatasIds.split(",");
		for(String dataID : dataIDs){
			datas.add(dataID);
		}
	}


	/**
	 * 功能描述:将本次产生的交易添加至缓存<br>
	 * @param houseItem
	 * @param transactionId<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void addDatasRtransaction(String chargeDatasIds, Long transactionId,final List<Object[]> datasRTransaction) {
		String dataIDs[]=chargeDatasIds.split(",");
		for(String dataID : dataIDs){
			datasRTransaction.add(new Object[]{dataID,transactionId});
		}
	}

	/**
	 * 功能描述:使用HIBERNATE对走表费用的交易对象持久化<br>
	 * @param userId
	 * @param period
	 * @param subAccountId
	 * @param houseItem
	 * @param meterVersion
	 * @param amt
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private DebitTransDomain saveMeterDebitTransDomain(SysInfo currentSysInfo, PeriodDomain period, Long subAccountId, ArCalculateModel houseItem, MeterVersion meterVersion, BigDecimal amt) {
		DebitTransDomain debitTransDomain=new DebitTransDomain();
		debitTransDomain.setHouse(houseDao.findById( houseItem.getHouseId() ));
		debitTransDomain.setDebit(amt);
		debitTransDomain.setBusinessCode(businessCodeDao.findById(houseItem.getBizCodeId()));
		debitTransDomain.setStaVersion(meterVersion);
		debitTransDomain.setBindingAccount(subAccountDao.findById( subAccountId ));
		debitTransDomain.setPeriod(period);
		debitTransDomain.setClazz(SysrefcodeDO.FEE_TRANSACTION_CLAZZ_PRINCIPAL);
		debitTransDomain.setStatuz(SysrefcodeDO.FEE_TRANSACTION_STATUZ_NOTPAY);
		debitTransDomain.setSysInfo(currentSysInfo);
		arCalculateDao.saveObject(debitTransDomain);
		return debitTransDomain;
	}

	/**
	 * 功能描述:如果存在原始数据交易，则将原始数据交易关系数据持久化<br>
	 * <br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-4<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void addBatchDatasRTransaction(final List<Object[]> datasRTransaction){
		arCalculateDao.addBatchDatasRTransaction(datasRTransaction);
	}

	/**
	 * 功能描述:更新原始数据的状态为已经计算<br>
	 * <br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-4<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void updateBatchDatasStatus(final List<String> datas){
		List<Object []> datasIds=new ArrayList<Object[]>();
		for(String item : datas){
			datasIds.add(new Object[]{SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_COUNTED,item});
		}
		arCalculateDao.updateBatchDatasStatus(datasIds);
		logger.info("原始数据状态更新成功。更新了"+datasIds.size()+"条");
	}

	/**
	 * 功能描述:更新子帐户余额<br>
	 * <br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-2<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void updateSubAccountBalance() {
		List<Object[]> parameterList=new ArrayList<Object[]>();
		for(Long subAccountId : subAccountBalances.get().keySet()){
			Object[] parameter=new Object[]{subAccountBalances.get().get(subAccountId),subAccountId};
			parameterList.add(parameter);
		}
		arCalculateDao.updateSubAccountBalance(parameterList);
		subAccountBalances.get().clear();
	}


	/**
	 * 功能描述:指定收费管理区下的所有楼栋里的房间的费用入帐<br>
	 * @param userId
	 * @param period
	 * @param chargePrecinct<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-2<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void comptabiliserWithChargePrecinct(int type,Long userId, PeriodDomain period,Map<Long,SubAccountBean> subAccount) {
		Set<BuildingDomain> buildings = period.getChargePrecinct().getBuildings();
		for(BuildingDomain building :  buildings){
			comptabiliserWithBuilding(type,userId, period, building,subAccount);
		}
	}

	/**
	 * 功能描述:指定楼栋下的所有房间的费用入帐<br>
	 * @param userId
	 * @param period
	 * @param building<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-2<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void comptabiliserWithBuilding(int type,Long userId, PeriodDomain period,BuildingDomain building,Map<Long,SubAccountBean> subAccount) {
		int pageNO=1;
		List<ArCalculateModel> houseList=null;
		do{
			if(type==FIXED){
				houseList=arCalculateDao.getHouseListWithFixed(period, building.getKeyword(), pageNO,PAGESIZE);
			}else if(type==GENERAL){
				houseList=arCalculateDao.getHouseListWithGeneral(period, building.getKeyword(), pageNO,PAGESIZE);
			}

			if( houseList.size()>0 ){
				comptabiliser(userId, period.getKeyword(), houseList,subAccount);
				countBalance(houseList,subAccount);
			}
			pageNO++;
		}while( houseList!=null && houseList.size() == PAGESIZE);
	}

	/**
	 * 功能描述:统计帐户余额<br>
	 * @param houseList<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-2<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void countBalance(List<ArCalculateModel> houseList,Map<Long,SubAccountBean> subAccount){
		for(ArCalculateModel houseItem : houseList){
			SubAccountBean subAccountBean = subAccount.get(houseItem.getHouseId());
			if(!checkSubAccountStatus(houseItem.getHouseId(), subAccountBean)){
				continue;
			}
			addBalance(subAccountBean.getSubAccountId(), houseItem.getAmt());
		}
	}

	/**
	 * 功能描述:累计帐户金额<br>
	 * @param subAccountId
	 * @param amt
	 * Create author:罗军林<br>
	 * Create on:2008-9-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void addBalance(Long subAccountId,BigDecimal subAccountBalance) {
		if(subAccountBalances.get().get(subAccountId)==null){
			subAccountBalances.get().put(subAccountId, subAccountBalance);
		}else{
			subAccountBalances.get().put(subAccountId, subAccountBalances.get().get(subAccountId).add(subAccountBalance));
		}
	}

	/**
	 * 功能描述:将查询结果批量入帐<br>
	 * @param userId
	 * @param period
	 * @param houseListWithGeneral<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-2<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void comptabiliser(Long userId, Long periodId, List<ArCalculateModel> houseListWithGeneral,Map<Long,SubAccountBean> subAccount) {
		List<Object[]> parameterList = wrapHouseList(userId, periodId, houseListWithGeneral,subAccount);
		arCalculateDao.insertTransaction(parameterList);
	}


	/**
	 * 功能描述:给房间列表的每个房间加上周期ID、交易状态、交易类型<br>
	 * @param userId
	 * @param prechinect
	 * @param houseList
	 * @return<br>
	 * Create author:罗军林<br>
	 * Create on:2008-9-1<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private List<Object[]> wrapHouseList(Long userId, Long periodId, List<ArCalculateModel> houseList,Map<Long,SubAccountBean> subAccount) {
		List<Object[]> parameterList=new ArrayList<Object[]>();
		for(ArCalculateModel houseItem : houseList){
			SubAccountBean subAccountBean = subAccount.get(houseItem.getHouseId());
			if(!checkSubAccountStatus(houseItem.getHouseId(), subAccountBean) || BigDecimal.ZERO.compareTo(houseItem.getAmt())>=0){
				continue;
			}
			Object[] parameter={
					houseItem.getHouseId(),
					houseItem.getAmt(),
					houseItem.getBizCodeId(),
					houseItem.getChargeStaVerionId(),
					subAccountBean.getSubAccountId(),
					SysrefcodeDO.FEE_TRANSACTION_CLAZZ_PRINCIPAL,
					SysrefcodeDO.FEE_TRANSACTION_STATUZ_NOTPAY,
					periodId,
					userId
			};
			parameterList.add(parameter);
		}
		return parameterList;
	}

	/**
	 * 功能描述:检查帐户的状态，如果帐户不存在，则终止操作，如果帐户锁定，则返回false,其它返回true<br>
	 * @param houseId
	 * @param subAccountBean<br>
	 * Create author:罗军林<br>
	 * Create on:2008-10-22<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private boolean checkSubAccountStatus(Long houseId, SubAccountBean subAccountBean) {
		if( null==subAccountBean ){
			HouseDomain houseDomain= houseDao.findById(houseId);
			throw new BusinessException("charge:chargeAccount_is_invalidation,"+houseDomain.getHouseNumber(),BusinessException.ERROR);
		}else if( subAccountBean.isLockedDebit() ){
			logger.info("房号ID为"+houseId+"的收费帐户贷方被锁。急略本房间本次操作！");
			return false;
		}
		return true;
	}


	/**
	 * 功能描述:检查是否做过应收计算<br>
	 * @param periodList<br>
	 * Create author:罗军林<br>
	 * Create on:2008-10-10<br>
	 * Edit author:<br>
	 * Edit on:<br>
	 * Why:<br>
	 */
	private void checkIsCaculate(List<PeriodDomain> periodList) {
		if(periodList==null || periodList.size()==0){
			throw new BusinessException( "charge:has_calculate",BusinessException.ERROR);
		}
//		for(PeriodDomain period : periodList){
//			List<ChargeDatasDomain> chargeDatas= meterDataRegisterDao.getMeterDatasListByPeriodId(period.getKeyword());
//			if( null==chargeDatas || chargeDatas.size()<=0){
//				throw new BusinessException("收费周期"+period.getPeriod()+"没有新建状态的原始走表数据，不能做应收计算",BusinessException.WARNING);
//			}
//		}
	}


	public void setArCalculateDao(IArCalculateDao arCalculateDao) {
		this.arCalculateDao = arCalculateDao;
	}

	public void setBusinessCodeDao(IBusinessCodeDao businessCodeDao) {
		this.businessCodeDao = businessCodeDao;
	}

	public void setHouseDao(IHouseDao houseDao) {
		this.houseDao = houseDao;
	}
	public void setMeterVersionDao(IMeterVersionDao meterVersionDao) {
		this.meterVersionDao = meterVersionDao;
	}

	public void setSubAccountDao(ISubAccountDao subAccountDao) {
		this.subAccountDao = subAccountDao;
	}

	public void setGeneralVersionDao(IGeneralVersionDao generalVersionDao) {
		this.generalVersionDao = generalVersionDao;
	}

	public void setPeriodLogDao(IPeriodLogDao periodLogDao) {
		this.periodLogDao = periodLogDao;
	}

	public void setFlowDefDao(IFlowDefDao flowDefDao) {
		this.flowDefDao = flowDefDao;
	}

	/**
	 * @param charStoChoMeterDao the charStoChoMeterDao to set
	 */
	public void setCharStoChoMeterDao(ICharStoChoMeterDao charStoChoMeterDao) {
		this.charStoChoMeterDao = charStoChoMeterDao;
	}

	public void setMeterDataRegisterDao(IMeterDataRegisterDao meterDataRegisterDao) {
	}

}
